import sys
import re
import traceback
from typing import Callable, Union, List, TypedDict, Dict
import json
import can
import isotp
import threading
import time
from can.interfaces.socketcan import SocketcanBus
from udsoncan.configs import default_client_config
from udsoncan import Response
from udsoncan import services
from udsoncan.connections import PythonIsoTpConnection
from udsoncan.client import Client
from udsoncan.exceptions import *
from udsoncan.services import *
from udsoncan.typing import ClientConfig
import udsoncan.configs
import struct

from Common import CommonFunc, ReadRemainingDataCodec
from DataStruct import *

globallogger = CommonFunc.InitLogging("Uds.log", "main")
    
class Codec9005(udsoncan.DidCodec):

    # Offsets confirmed from real frames:
    U41_OFFSET = (30, 32)    # bytes 30-31
    U42_OFFSET = (24, 26)    # bytes 26-27

    SCALE = 0.1

    def encode(self, values: dict):
        """
        values = {"U41": val41, "U42": val42}
        """
        u41_raw = int(values["U41"] / self.SCALE)
        u42_raw = int(values["U42"] / self.SCALE)

        return (
            u41_raw.to_bytes(2, "big", signed=True) +
            u42_raw.to_bytes(2, "big", signed=True)
        )

    def decode(self, payload: bytes):
        # U41
        s, e = self.U41_OFFSET
        raw41 = int.from_bytes(payload[s:e], "big", signed=True)
        U41 = raw41 * self.SCALE

        # U42
        s, e = self.U42_OFFSET
        raw42 = int.from_bytes(payload[s:e], "big", signed=True)
        U42 = raw42 * self.SCALE

        return {
            "U41": U41,
            "U42": U42
        }

    def __len__(self):
        return 69  # variable-length DID





class Codec902A(udsoncan.DidCodec):
    def encode(self, val: dict):
        # val = {"quantity": int, "percentage": float}
        quantity = val.get("quantity", 0)
        percentage = val.get("percentage", 0.0)

        q_bytes = quantity.to_bytes(4, 'big')
        p_raw = int(percentage * 100)
        p_bytes = p_raw.to_bytes(2, 'big')

        return q_bytes + p_bytes

    def decode(self, payload: bytes):
        quantity = int.from_bytes(payload[0:4], 'big')
        percent_raw = int.from_bytes(payload[6:8], 'big')
        percentage = percent_raw / 100.0
        return {
            "quantity": quantity,
            "percentage": percentage
        }

    def __len__(self):
        return 6

class Codec5C22(udsoncan.DidCodec):
    def encode(self, val: float):
        raw = int(val * 20)     # scale back
        return raw.to_bytes(2, 'big')

    def decode(self, payload: bytes):
        raw = int.from_bytes(payload[0:2], 'big')
        value = raw / 20.0
        return {"value": value}

    def __len__(self):
        return 2

class Codec5C23(udsoncan.DidCodec):
    def encode(self, val: float):
        raw = int(val * 2)
        return raw.to_bytes(1, 'big')

    def decode(self, payload: bytes):
        raw = payload[0]
        value = raw / 2.0
        return {"value": value}

    def __len__(self):
        return 1



class UdsClient(Client):    

    logger = CommonFunc.InitLogging("Uds.log", "UdsClient")
    ExcuteResult:bool = True
    def __init__(self,
                 trans:TransConfig, # 描述can通讯参数
                 udsconfig:ClientConfig = None,    # 描述uds会话参数
                 BusID:str = 0,
                 keep_alive_interval: int = 1  # 默认3秒间隔
                 ) -> None:
        isotp_params = {
            'stmin': 32,                            # Will request the sender to wait 32ms between consecutive frame. 0-127ms or 100-900ns with values from 0xF1-0xF9
            'blocksize': 8,                         # Request the sender to send 8 consecutives frames before sending a new flow control message
            'wftmax': 0,                            # Number of wait frame allowed before triggering an error
            'tx_data_length': 8,                    # Link layer (CAN layer) works with 8 byte payload (CAN 2.0)
            # Minimum length of CAN messages. When different from None, messages are padded to meet this length. Works with CAN 2.0 and CAN FD.
            'tx_data_min_length': None,
            'tx_padding': 0x00,                        # Will pad all transmitted CAN messages with byte 0x00.
            'rx_flowcontrol_timeout': 1000,         # Triggers a timeout if a flow control is awaited for more than 1000 milliseconds
            'rx_consecutive_frame_timeout': 1000,   # Triggers a timeout if a consecutive frame is awaited for more than 1000 milliseconds
            #  'squash_stmin_requirement': False,      # When sending, respect the stmin requirement of the receiver. If set to True, go as fast as possible.
            'max_frame_size': 4095,                 # Limit the size of receive frame.
            'can_fd': True,                        # Does not set the can_fd flag on the output CAN messages
            'bitrate_switch': False,                # Does not set the bitrate_switch flag on the output CAN messages
            'rate_limit_enable': False,             # Disable the rate limiter
            #  'rate_limit_max_bitrate': 1000000,      # Ignored when rate_limit_enable=False. Sets the max bitrate when rate_limit_enable=True
            'rate_limit_window_size': 0.2,          # Ignored when rate_limit_enable=False. Sets the averaging window size for bitrate calculation when rate_limit_enable=True
            'listen_mode': False,                   # Does not use the listen_mode which prevent transmission.
        }
        self.If = trans
        #default config
        uds_config = udsoncan.configs.default_client_config.copy()
        uds_config['exception_on_negative_response'] = False
        uds_config['exception_on_invalid_response'] = False
        uds_config['exception_on_unexpected_response'] = False
        uds_config['use_server_timing'] = False
        from genkey import seed2key
        uds_config['security_algo'] = seed2key
        #user difine
        for key, value in udsconfig.items():
            uds_config[key] = CommonFunc.convert_value(key, value)

        uds_config['request_timeout'] = 10
        uds_config['p2_timeout'] = 5
        uds_config['p2_star_timeout'] = 10
        uds_config['data_identifiers'] = {
            # 0xFD00 : udsoncan.AsciiCodec(48),
            0x902A: Codec902A,          # 可以给类
            0x5C22: Codec5C22,        # 也可以给实例
            0x5C23: Codec5C23,
            0x9005: Codec9005,
            'default' : ReadRemainingDataCodec
        }
        uds_config['input_output'] = {
            # 0xFD00 : udsoncan.AsciiCodec(48),
            0x5C02: '>B',  # 主正继电器，大端2字节
            0x5C03: '>B',  # 主负继电器，大端2字节
            0x5D67: '>B',  # 主负继电器，大端2字节
        } 
        # 会话保持相关属性
        self.keep_alive_interval = keep_alive_interval
        self.keep_alive_thread = None
        self.keep_alive_running = False
        try:
            # bus_id_str = str(self.If['BusID'])   # 无论是数字还是字符串都转成字符串
            bus = SocketcanBus('can' + BusID, fd=True)
            # bus = SocketcanBus('can0', fd = True)  
            notifier = can.Notifier(bus, [], timeout=1.0)
            # print(self.If['FrameType'])
            # print(int(self.If['RequestID'], 16))
            # print(int(self.If['ResponseID'], 16))

            tp_addr = isotp.Address(isotp.AddressingMode[self.If['FrameType']], txid = int(self.If['RequestID'], 16), rxid = int(self.If['ResponseID'], 16))
            stack = isotp.NotifierBasedCanStack(bus=bus, notifier=notifier, address=tp_addr, params=isotp_params) # Network/Transport layer (IsoTP protocol). Register a new listenenr
            socketconn = PythonIsoTpConnection(stack)# interface between Application and Transport layer
            
            super().__init__(conn = socketconn, config = uds_config)
            self.open()

   # ...
        except Exception as e:
            self.logger.error(traceback.format_exc())
            self.close()
    def _start_keep_alive(self):
        """启动会话保持线程"""
        if self.keep_alive_running:
            return
            
        self.keep_alive_running = True
        self.keep_alive_thread = threading.Thread(target=self._keep_alive_worker, daemon=True)
        self.keep_alive_thread.start()
        self.logger.debug("Session keep-alive started")

    def _keep_alive_worker(self):
        """会话保持工作线程"""
        while self.keep_alive_running:
            try:
                # 直接调用udsoncan的tester_present方法
                self.tester_present()
                self.logger.debug("Sent session keep-alive")
            except Exception as e:
                self.logger.error(f"Keep-alive error: {e}")
            
            # 固定间隔休眠
            time.sleep(self.keep_alive_interval)

    def change_session(self, session):
        """重写change_session方法，自动管理会话保持"""
        response = super().change_session(session)
        
        # 如果切换到非默认会话，启动保持
        if session != 0x01:
            self._start_keep_alive()
        
        return response



# 在类顶（UdsClient）加上白名单（若已存在则可省略）
    DTC_WHITELIST = {
        'D06287', 'D07087', 'D06687', 'C29300', 'D09687', 'C10000', 'D08E87',
        'E12283', 'E12883', 'E12983', '100304',
        'D40C61', 'D40D43', 'D40E06', 'D40255', 'D40355', 'D40755', 'D40855'
    }

    def Proc(self, flow:UdsStepModel) -> dict:
        ParmValue:list = flow['ParmValue']
        req = None

        try:
            if flow['FuncName'] == '$10':
                session = int(ParmValue[0], 16)
                req = self.change_session(session)

            elif flow['FuncName'] == '$2F':
                # ParmValue 格式示例: ["0x5C02", "0x0301"]
                did = int(ParmValue[0], 16)
                data_value = ParmValue[1]

                if isinstance(data_value, str) and data_value.startswith('0x'):
                    data_value = data_value[2:]
                if len(data_value) % 2 != 0:
                    data_value = '0' + data_value
                value_int = int(data_value, 16)
                control_param = (value_int >> 8) & 0xFF
                io_value = value_int & 0xFF

                print(f"DID=0x{did:04X}, control_param=0x{control_param:02X}, value=0x{io_value:02X}")

                resp = self.io_control(
                    did=did,
                    control_param=control_param,
                    values=[io_value]
                )

                # 只关心成功与否
                raw_response = self.ExcuteAndGenresponse(resp)
                return {
                    'valid': raw_response['valid'],
                    'invalid_reason': raw_response['invalid_reason'],
                    'positive': raw_response['positive'],
                    'data': '',               # 不返回数据
                    'analysed_data': ''       # 不解析具体值
                }

            elif flow['FuncName'] == '$2E':
                did = int(ParmValue[0], 16)
                data_value = ParmValue[1]

                # 判断类型
                if isinstance(data_value, str) and data_value.startswith('0x'):
                    # 十六进制整数形式，例如 0x0301
                    value = int(data_value, 16)
                elif isinstance(data_value, str) and all(32 <= ord(c) <= 126 for c in data_value):
                    # 全是可显示ASCII字符，例如 "BAT1234"
                    value = data_value
                else:
                    # 尝试数字形式
                    try:
                        value = int(data_value)
                    except ValueError:
                        value = data_value.encode('utf-8')  # fallback

                print(f"DID: {did} (0x{did:04X})")
                print(f"Value: {value} ({type(value).__name__})")

                req = self.write_data_by_identifier(did, value)
                raw_response = self.ExcuteAndGenresponse(req)

                
            elif flow['FuncName'] == '$27':
                if ParmValue:
                    level = int(ParmValue[0], 16)
                    req = self.unlock_security_access(level)

            elif flow['FuncName'] == '$22':
                id = int(ParmValue[0], 16)
                # 发起读DID请求并立即把Response对象用ExcuteAndGenresponse处理得到原始hex等信息
                resp = self.read_data_by_identifier(id)
                raw_response = self.ExcuteAndGenresponse(resp)

                analysed_data = None

                try:
                    # resp.service_data.values 是一个字典（如果 DidCodec 已注册，udsoncan 会把解析后的值放在这里）
                    service_values = getattr(resp.service_data, 'values', None) or {}

                    # 优先使用请求中的 DID 作为键取值
                    if id in service_values:
                        did_value = service_values[id]
                    else:
                        # 否则尝试取第一个可用的 value（多个 DID 的情况下）
                        try:
                            did_value = next(iter(service_values.values()))
                        except StopIteration:
                            did_value = None

                    # 根据 did_value 的类型选择合适的序列化方式
                    if isinstance(did_value, (bytes, bytearray)):
                        # 直接把 bytes 转成 HEX 字符串（大写）
                        analysed_data = did_value.hex().upper() if did_value else ""
                    elif isinstance(did_value, dict):
                        # Codec 返回结构化 dict（例如 {"quantity": ..., "percentage": ...}）
                        analysed_data = safe_json_dumps(did_value)
                    elif did_value is None:
                        # 没有从 service_data 中拿到值，使用 raw_response['data'] 回退（它已经是 hex 字符串或 json）
                        analysed_data = raw_response.get('data', '')
                    else:
                        # 数字或字符串等直接转为可读形式（字符串或 json）
                        try:
                            # 如果是可 JSON 化的对象，优先用 safe_json_dumps，以保证 bytes 等被正确处理
                            analysed_data = safe_json_dumps(did_value)
                        except Exception:
                            analysed_data = str(did_value)

                except Exception as e:
                    # 万一发生解析错误，记录日志并回退到 raw_response['data']
                    self.logger.error(f"Error extracting DID value: {e}")
                    self.logger.error(traceback.format_exc())
                    analysed_data = raw_response.get('data', '')

                return {
                    'valid': raw_response['valid'],
                    'invalid_reason': raw_response['invalid_reason'],
                    'positive': raw_response['positive'],
                    'data': raw_response['data'],
                    'analysed_data': analysed_data
                }


            elif flow['FuncName'] == '$14':
                group = int(ParmValue[0], 16)
                req = self.clear_dtc(group)

            elif flow['FuncName'] == '$19':
                # 读取DTC服务
                status_mask = int(ParmValue[0], 16) if ParmValue else 0xFF

                # 使用类内白名单
                whitelist = getattr(self, 'DTC_WHITELIST', set())

                # 调用udsoncan获取响应
                resp = self.get_dtc_by_status_mask(status_mask)

                # 无响应的情况
                if resp is None:
                    return {
                        'valid': False,
                        'invalid_reason': 'NO_RESPONSE',
                        'positive': False,
                        'data': '',
                        'analysed_data': {  # 直接使用字典对象
                            'dtc_count': 0,
                            'whitelisted_count': 0,
                            'unwhitelisted_count': 0,
                            'dtc_list': []
                        }
                    }

                # 获取原始响应用于Response字段
                raw_response = self.ExcuteAndGenresponse(resp)
                
                # 响应无效的情况
                if not raw_response['valid']:
                    return {
                        'valid': raw_response['valid'],
                        'invalid_reason': raw_response['invalid_reason'],
                        'positive': raw_response['positive'],
                        'data': raw_response['data'],
                        'analysed_data': raw_response['data']  # 无效时AnalyseData与Response相同
                    }

                # 响应有效：提取DTC列表并构造解析结果
                try:
                    dtcs = getattr(resp.service_data, 'dtcs', []) or []
                except Exception:
                    dtcs = []

                dtc_list = []
                whitelisted_count = 0

                for d in dtcs:
                    # 解析DTC ID
                    dtc_id_int = None
                    dtc_id_str = None
                    try:
                        dtc_id_int = int(d.id)
                        dtc_id_str = f"{dtc_id_int:06X}"
                    except Exception:
                        try:
                            raw = str(getattr(d, 'id', '')).upper()
                            dtc_id_int = int(raw, 16)
                            dtc_id_str = f"{dtc_id_int:06X}"
                        except Exception:
                            dtc_id_int = 0
                            dtc_id_str = str(getattr(d, 'id', '')).upper() or "000000"

                    # 获取状态字节
                    try:
                        status_byte = int(getattr(d, 'status', 0)) & 0xFF
                    except Exception:
                        status_byte = 0

                    # 判断是否在白名单内
                    is_whitelisted = (dtc_id_str in whitelist)
                    if is_whitelisted:
                        whitelisted_count += 1

                    dtc_list.append({
                        'dtc_id': dtc_id_str,
                        'status': f"0x{status_byte:02X}",
                        'whitelisted': is_whitelisted
                    })

                # 构建解析后的数据
                unified_data = {
                    'dtc_count': len(dtc_list),
                    'whitelisted_count': whitelisted_count,
                    'unwhitelisted_count': len(dtc_list) - whitelisted_count,
                    'dtc_list': dtc_list
                }
                
                return {
                    'valid': True,
                    'invalid_reason': None,
                    'positive': getattr(resp, 'positive', True),
                    'data': raw_response['data'],  # 原始hex数据
                    'analysed_data': unified_data  # 直接使用字典对象
                }

            else:
                self.logger.error('Wrong FuncName %s', flow['FuncName'])
                raise KeyError(f'Wrong FuncName {flow["FuncName"]}')

            # 其他服务统一处理
            if req is None:
                raise ValueError("Request is None")
                
            raw_response = self.ExcuteAndGenresponse(req)
            # 对于其他服务，AnalyseData与Response相同
            return {
                'valid': raw_response['valid'],
                'invalid_reason': raw_response['invalid_reason'],
                'positive': raw_response['positive'],
                'data': raw_response['data'],
                'analysed_data': raw_response['data']  # 其他服务AnalyseData与Response相同
            }

        except Exception as e:
            self.logger.error(f"Proc error: {e}")
            self.logger.error(traceback.format_exc())
            return {
                'valid': False,
                'invalid_reason': str(e),
                'positive': False,
                'data': '',
                'analysed_data': ''
            }

            # self.essentialfuncptr= {
            # '$10':self.change_session,# newsession: int
            # '$27':self.unlock_security_access, # level, seed_params=bytes()
            # '$22':self.read_data_by_identifier, # Union[int, List[int]]
            # '$2E':self.write_data_by_identifier, #did: int, value: Any
            # '$14':self.clear_dtc, # group: int = 0xFFFFFF
            # '$19':self.get_dtc_by_status_mask, # status_mask: int
            # '$2F':self.io_control # status_mask: int
            # }
        
    def ExcuteAndGenresponse(self, CertainResponse):
        Red = {}
        try:
            Red['valid'] = bool(getattr(CertainResponse, 'valid', False))
            Red['positive'] = bool(getattr(CertainResponse, 'positive', False))
            
            # 执行成功的条件是：响应有效且为正响应
            is_success = Red['valid'] and Red['positive']
            
            if not is_success:
                self.ExcuteResult = False

            Red['invalid_reason'] = getattr(CertainResponse, 'invalid_reason', None)

            # 处理data字段，确保转换为合适的格式
            data_field = getattr(CertainResponse, 'data', None)
            if data_field is None:
                Red['data'] = ''
            elif isinstance(data_field, (bytes, bytearray)):
                # 将bytes转换为十六进制字符串
                if data_field:
                    Red['data'] = data_field.hex().upper()
                else:
                    Red['data'] = ''
            elif isinstance(data_field, (dict, list)):
                Red['data'] = safe_json_dumps(data_field)
            else:
                Red['data'] = str(data_field)
                
        except Exception as e:
            self.logger.error(f"ExcuteAndGenresponse error: {e}")
            Red = {
                'valid': False,
                'positive': False,
                'invalid_reason': str(e),
                'data': ''
            }
            self.ExcuteResult = False
        return Red
   
     
"""    python3 ClientDriver.py "{"RequestID":"0x0","ResponseID":"0x1","FrameType":"Standard","SendFilled":null}" "{"p2_timeout":"0","ignore_all_zero_dtc":"true"}" "{"9":{"FuncName":"$10","ParmName":["诊断会话类型"],"ParmType":["int"],"ParmValue":["0x00"],"RawRequest":"10 00","ExpectedResponse":"50 00"}}"

"""



def main():
    returnentity = {}
    number = "0"
    
    # 使用字典结构而不是字符串
    res = {
        "OutItem": {},
        "Result": True,  # 默认为True，如果有任何步骤失败则设为False
        "Error": None
    }

    try:
        # 解析输入文件名
        filename = sys.argv[1]
        BusID = sys.argv[2]
        globallogger.debug(f"filename {filename}")

        match = re.search(r'UdsArgs(\d+)\.json', filename)
        if match:
            number = match.group(1)
        else:
            globallogger.error(f"input file {filename} not found or wrong format")

        # 读取 JSON 文件
        with open(filename, 'r', encoding='utf-8') as file:
            data = json.load(file)
            globallogger.debug(f"Raw data from file: {data}")
            
            if len(data) != 3:
                raise ValueError(f"{filename} has less than 3 args, got {len(data)}")

            # 解析配置
            trans_config_data = data[0] if isinstance(data[0], dict) else json.loads(data[0])
            client_config_data = data[1] if isinstance(data[1], dict) else json.loads(data[1])
            uds_step_model_data = data[2] if isinstance(data[2], dict) else json.loads(data[2])
            
            globallogger.debug(f"trans_config: {trans_config_data}")
            globallogger.debug(f"client_config: {client_config_data}")
            globallogger.debug(f"uds_step_model: {uds_step_model_data}")

            trans_config = TransConfig(**trans_config_data)
            client_config = ClientConfig(**client_config_data)
            uds_step_model = UdsStepModel(**uds_step_model_data)

        # 执行 UDS 流程
        with UdsClient(trans_config, client_config, BusID) as Ucli:
            globallogger.debug(f"UdsStepModel keys: {list(uds_step_model.keys())}")
            globallogger.debug(f"UdsStepModel length: {len(uds_step_model)}")
            
            for key, value in uds_step_model.items():
                globallogger.debug(f"Processing step {key}: {value}")
                try:
                    proc_result = Ucli.Proc(value)
                    globallogger.debug(f"Proc result: {proc_result}")
                    
                    # 提取Response和AnalyseData
                    response_data = proc_result.get('data', '')
                    analyse_data = proc_result.get('analysed_data', response_data)
                    
                    # 确保Response是hex格式
                    response_hex = format_hex(response_data)
                    
                    # 执行状态：valid为True且positive为True才算成功
                    is_valid = bool(proc_result.get('valid', False))
                    is_positive = bool(proc_result.get('positive', False))
                    status_bool = is_valid and is_positive
                    
                    # 如果任何一步失败，设置整体结果为False
                    if not status_bool:
                        Ucli.ExcuteResult = False
                    
                    # 日志信息：根据执行状态生成不同的日志
                    if is_valid and is_positive:
                        logs = "Success"
                    elif is_valid and not is_positive:
                        # 有效但为负响应
                        negative_reason = proc_result.get('invalid_reason', 'NegativeResponse')
                        logs = f"NegativeResponse: {negative_reason}"
                    else:
                        # 无效响应
                        invalid_reason = proc_result.get('invalid_reason', 'InvalidResponse')
                        logs = f"InvalidResponse: {invalid_reason}"

                except Exception as e:
                    status_bool = False
                    logs = f"[{type(e).__name__}] {e}"
                    response_hex = ""
                    analyse_data = ""
                    Ucli.ExcuteResult = False

                item = {
                    "Response": response_hex,
                    "RetryCount": 1,
                    "errcode": 4,
                    "Status": status_bool,
                    "Logs": logs,
                    "AnalyseData": analyse_data
                }
                returnentity[key] = item
                globallogger.debug(f"Added item for step {key}: {item}")

            globallogger.debug(f"Final returnentity: {returnentity}")
            globallogger.debug(f"Final ExcuteResult: {Ucli.ExcuteResult}")

            if len(returnentity) != len(uds_step_model):
                globallogger.warning(f"Steps count mismatch: expected {len(uds_step_model)}, got {len(returnentity)}")
                Ucli.ExcuteResult = False

            # 检查是否有任何步骤失败
            for step_key, step_result in returnentity.items():
                if not step_result.get('Status', False):
                    Ucli.ExcuteResult = False
                    break

            # 直接使用对象而不是字符串
            res = {
                "OutItem": returnentity,  # 直接使用字典对象
                "Result": Ucli.ExcuteResult,  # 直接使用布尔值
                "Error": None
            }

    except Exception as e:
        globallogger.error(f"Main function error: {traceback.format_exc()}")
        res = {
            "OutItem": returnentity,  # 直接使用字典对象
            "Result": False,  # 直接使用布尔值
            "Error": f"[{type(e).__name__}] {e}"
        }

    finally:
        try:
            outfile = f"Udsoutput{number}.json"
            # 使用json.dumps确保输出是标准JSON格式
            with open(outfile, "w", encoding="utf-8") as f:
                json.dump(res, f, ensure_ascii=False, indent=2)
            globallogger.debug(f"写出结果文件 {outfile}")
            globallogger.debug(f"Final result: {res}")
        except Exception as e:
            globallogger.error(f"写出结果失败: {e}")

# 确保format_hex函数存在
def format_hex(data):
    """统一格式化 hex 输出，支持 bytes / str"""
    if data is None:
        return ""
    if isinstance(data, (bytes, bytearray)):
        if not data:  # 空bytes
            return ""
        return ' '.join(f'{b:02X}' for b in data)
    elif isinstance(data, str):
        data = data.strip().replace(" ", "")
        if not data:  # 空字符串
            return ""
        if len(data) % 2 != 0:
            data = '0' + data
        return ' '.join([data[i:i+2].upper() for i in range(0, len(data), 2)])
    return str(data)

# 确保safe_json_dumps函数存在
def safe_json_dumps(obj, **kwargs):
    """确保能安全序列化所有类型（bytes、bytearray、异常对象等）"""
    def default(o):
        if isinstance(o, (bytes, bytearray)):
            return o.hex().upper()  # 转16进制字符串
        if isinstance(o, Exception):
            return f"[Exception] {type(o).__name__}: {o}"
        return str(o)
    
    # 确保ensure_ascii参数不会重复
    kwargs.setdefault('ensure_ascii', False)
    return json.dumps(obj, default=default, **kwargs)

# 确保ExcuteAndGenresponse方法正确实现
def ExcuteAndGenresponse(self, CertainResponse):
    Red = {}
    try:
        Red['valid'] = bool(getattr(CertainResponse, 'valid', False))
        Red['positive'] = bool(getattr(CertainResponse, 'positive', False))
        
        # 执行成功的条件是：响应有效且为正响应
        is_success = Red['valid'] and Red['positive']
        
        if not is_success:
            self.ExcuteResult = False

        Red['invalid_reason'] = getattr(CertainResponse, 'invalid_reason', None)

        # 处理data字段，确保转换为合适的格式
        data_field = getattr(CertainResponse, 'data', None)
        if data_field is None:
            Red['data'] = ''
        elif isinstance(data_field, (bytes, bytearray)):
            # 将bytes转换为十六进制字符串
            if data_field:
                Red['data'] = data_field.hex().upper()
            else:
                Red['data'] = ''
        elif isinstance(data_field, (dict, list)):
            Red['data'] = safe_json_dumps(data_field)
        else:
            Red['data'] = str(data_field)
            
    except Exception as e:
        self.logger.error(f"ExcuteAndGenresponse error: {e}")
        Red = {
            'valid': False,
            'positive': False,
            'invalid_reason': str(e),
            'data': ''
        }
        self.ExcuteResult = False
    return Red


if __name__ == "__main__":
    main()

# testmodule

# main(test_string, json_string, testflow)
# print(test_string)
# b = services.DiagnosticSessionControl.InterpretedResponse
# b.valid = False
# b.invalid_reason = "1111"
# b.data = bytes([65, 66, 67])
# b.positive = True
# print(b)
# a = UdsClient(test_string, json_string)

# c = a.ExcuteAndGenresponse(b)
# print("usingtest")
